package net.qhzw.vip.qiyu.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import net.qhzw.vip.qiyu.component.ServerConfig;
import net.qhzw.vip.qiyu.constant.SysConstants;
import net.qhzw.vip.qiyu.dto.ContractDto;
import net.qhzw.vip.qiyu.entity.*;
import net.qhzw.vip.qiyu.handler.ApiException;
import net.qhzw.vip.qiyu.handler.MyException;
import net.qhzw.vip.qiyu.mapper.DtsCarRentalMapper;
import net.qhzw.vip.qiyu.model.*;
import net.qhzw.vip.qiyu.service.*;
import net.qhzw.vip.qiyu.util.*;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class DtsCarRentalServiceImpl extends ServiceImpl<DtsCarRentalMapper, DtsCarRental>
        implements DtsCarRentalService {


    @Autowired
    private DtsUserService dtsUserService;

    @Autowired
    private DtsCarRentalMapper dtsCarRentalMapper;

    @Autowired
    private GuaranteeCompanyService guaranteeCompanyService;

    @Autowired
    private RepairCodeService repairCodeService;

    @Autowired
    private SysPostageService postageService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private SysContractService sysContractService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SysElectricVehBrandService electricVehBrandService;

    @Autowired
    private SysCommunityService sysCommunityService;

    @Autowired
    private GuaranteeSiteService guaranteeSiteService;

    @Autowired
    private SysPostageService sysPostageService;

    @Autowired
    private DtsUserBillService dtsUserBillService;

    @Autowired
    private UserBillService userBillService;

    @Autowired
    private DtsUserDeductionService dtsUserDeductionService;

    @Autowired
    private RepairMaintService repairMaintService;

    @Value("${minio.endpoint}")
    private String minioEndpoint;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PayService payService;

    @Autowired
    private DtsCarRentalRefundService dtsCarRentalRefundService;


    /***
     * 提交租车申请
     * @param communityId
     * @return
     */
    @Override
    public boolean userSubmitCarRentalApp(Long communityId) {
        //当前用户是否可以租车
        getUserIsCarRental();
        SysCommunity community = sysCommunityService.getById(communityId);
        if (community == null) {
            throw new ApiException("当前站点不可用, 请重新选择！");
        }
        Long userId = SecurityUtils.getUserId();
        DtsCarRental dtsCarRental = new DtsCarRental();
        dtsCarRental.setUserId(userId);
        dtsCarRental.setCreated(new Date());
        dtsCarRental.setId(IdWorker.getId());
        dtsCarRental.setCommunityId(communityId);
        dtsCarRental.setShopId(community.getShopId());
        DtsUser dtsUser = new DtsUser();
        dtsUser.setId(userId);
        dtsUser.setShopId(community.getShopId());
        dtsUserService.updateById(dtsUser);
        return save(dtsCarRental);
    }

    /***
     * 当前用户在租车合同内不可重复租车
     */
    private void getUserIsCarRental() {
        Long userId = SecurityUtils.getUserId();
        int count = count(new LambdaQueryWrapper<DtsCarRental>()
                .eq(DtsCarRental::getUserId, userId)
                .lt(DtsCarRental::getStatus, 4));
        if (count > 0) {
            throw new MyException("您已租车订单，不可重复租车！");
        }

    }


    /***
     * 校验日期
     * @param terminationDate
     */
    private void checkDate(String terminationDate) {
        if (MyDateUtils.getDateByString(terminationDate).compareTo(new Date()) < 0) {
            throw new MyException("不能选择小于当前的日期!");
        }
    }

    /***
     * 站点管理员提交租车申请
     * @param form
     * @return
     */
    @Override
    public boolean adminCarRentalApp(AdminCarRentalAppForm form) {
        //保存站点管理员提交数据
        DtsCarRental dtsCarRental = new DtsCarRental();
        dtsCarRental.setId(form.getId());
        dtsCarRental.setLease(form.getLease());
        dtsCarRental.setStatus((byte) 1);
        dtsCarRental.setAdminId(SecurityUtils.getUserId());
        dtsCarRental.setSubDate(new Date());
        //dtsCarRental.setRepairCodeId(form.getRepairCodeId());
        //dtsCarRental.setPostageId(form.getPostageId());
        //dtsCarRental.setElectricVehBrandId(form.getElectricVehBrandId());
        return updateById(dtsCarRental);
    }


    /****
     * 分页查询租车申请列表
     * @param page 分页参数
     * @param keywords  真实姓名 | 身份证号 | 手机号码
     * @return
     */
    @Override
    public Map<String, Object> findByPage(Page<DtsCarRental> page, String keywords) {
        Map<String, Object> result = new HashMap<>();
        Long communityId = getcommunityIdByUserId(SecurityUtils.getUserId());
        PageHelper.startPage((int) page.getCurrent(), (int) page.getSize());
        List<DtsCarRentalVo> dtsCarRentalVoList = dtsCarRentalMapper.findByPage(keywords, communityId);
        PageInfo<DtsCarRentalVo> pageInfo = new PageInfo<>(dtsCarRentalVoList);
        result.put("total", (int) pageInfo.getTotal());
        result.put("records", pageInfo.getList());
        return result;
    }


    /**
     * 根据当前登录人获取站点ID
     *
     * @param userId
     * @return
     */
    private Long getcommunityIdByUserId(Long userId) {
        //DtsUser dtsUser = dtsUserService.getById(userId);
        DtsUser dtsUser = dtsUserService.getOne(new LambdaQueryWrapper<DtsUser>().eq(DtsUser::getId, userId));
        if (dtsUser == null) {
            throw new MyException("当前管理员暂无站点");
        }
        return dtsUser.getCommunityId();
    }

    /***
     * 结算租车费用明细
     * @return
     */
    @Override
    public CarRentalCostsVo carRentalCosts(CarRentalCostsForm form) {
        Long shopId = SecurityUtils.getLoginUser().getShopId();
        if (shopId == 1) {
            throw new ApiException("您是超级管理员，不能操作此订单！");
        }
        log.info("结算租车费用明细: {}", JSON.toJSONString(form));
        check(form);
        DtsCarRental dtsCarRental = new DtsCarRental();
        CarRentalCostsVo carRentalCostsVo = new CarRentalCostsVo();
        carRentalCostsVo.setId(form.getId());
        carRentalCostsVo.setUserId(form.getUserId());
        //当前时间到下下月19号天数
        int nextMonth19day = (int) MyDateUtils.daysBetween(new Date(), MyDateUtils.getNextMonth19day()) + 1;
        if (nextMonth19day <= 30) {
            nextMonth19day = nextMonth19day + 30;
        }
        SysElectricVehBrand electricVehBrand = getElectricVehBrand(form.getLease(),
                form.getRepairCodeId(),
                form.getElectricVehBrandId(),
                shopId);
        //租户信息
        DtsUser dtsUserById = getDtsUserById(form.getUserId());
        carRentalCostsVo.setRealName(dtsUserById.getRealName());
        carRentalCostsVo.setIdCard(dtsUserById.getIdCard());
        carRentalCostsVo.setMobile(dtsUserById.getMobile());
        //担保信息
        GuaranteeCompany guaranteeCompany = getGuaranteeCompanyById(form);
        BigDecimal rent = new BigDecimal(0.0);
        //BigDecimal deposit = new BigDecimal(0.0);
        BigDecimal deposit = form.getDeposit();
        BigDecimal totalRent = null;
        BigDecimal advanceRcptRent = null;
        if (guaranteeCompany != null) {
            carRentalCostsVo.setGuaranteeCompanyName(guaranteeCompany.getName());
            carRentalCostsVo.setGuaranteeCompanyDeposit(guaranteeCompany.getDeposit());
            rent = electricVehBrand.getRent();
            totalRent = electricVehBrand.getRent().add(deposit);
            //totalRent.add(deposit);
            advanceRcptRent = electricVehBrand.getRent();
        } else {
            //deposit = getDeposit(form);
            advanceRcptRent = electricVehBrand.getDayRent().multiply(new BigDecimal(nextMonth19day));
            totalRent = electricVehBrand.getDayRent().multiply(new BigDecimal(nextMonth19day)).add(deposit);
        }
        carRentalCostsVo.setNextMonth19day(nextMonth19day);
        carRentalCostsVo.setUnitPrc(electricVehBrand.getDayRent());
        carRentalCostsVo.setDeposit(deposit);
        totalRent.add(deposit);
        carRentalCostsVo.setTotalRent(totalRent);
        carRentalCostsVo.setAdvanceRcptRent(advanceRcptRent);
        carRentalCostsVo.setLease(form.getLease());
        carRentalCostsVo.setRent(rent);
        if (form.getLease().intValue() == 1) {
            carRentalCostsVo.setRepairCode(repairCodeService.getById(form.getRepairCodeId()));
            dtsCarRental.setRepairCodeId(form.getRepairCodeId());
        }
        carRentalCostsVo.setOrderNumber(IdWorker.getId() + "");
        //调用微信支付
        log.info("【调用微信支付】");
        String payCode = getPayCode(shopId, carRentalCostsVo);
        log.info("【调用微信支付成功】");
        carRentalCostsVo.setPayCode(payCode);
        dtsCarRental.setNextMonth19day(nextMonth19day);
        dtsCarRental.setId(form.getId());
        dtsCarRental.setLease(form.getLease());
        dtsCarRental.setRent(rent);
        dtsCarRental.setDayRent(electricVehBrand.getDayRent());
        dtsCarRental.setDeposit(deposit);
        dtsCarRental.setTotalRent(totalRent);
        dtsCarRental.setAdvanceRcptRent(advanceRcptRent);
        dtsCarRental.setElectricVehBrandId(electricVehBrand.getId());
        updateById(dtsCarRental);
        return carRentalCostsVo;
    }

    /**
     * 生成支付二维码
     *
     * @param carRentalCostsVo
     * @return
     */
    private String getPayCode(Long shopId, CarRentalCostsVo carRentalCostsVo) {
        String payCode = payService.createNative(shopId, carRentalCostsVo);
        return payCode;
    }

    /**
     * 计算押金
     *
     * @param form
     * @return
     */
    private BigDecimal getDeposit(CarRentalCostsForm form) {
        BigDecimal deposit = new BigDecimal(0);
        //无担保公司押金最低1000
        if (getGuaranteeCompanyById(form) == null) {
            return form.getDeposit();
        }
        //1：整车 2：电池
        Long electricVehBrandId = 0L;
        if (form.getLease().intValue() == 1) {
            Long repairCodeId = form.getRepairCodeId();
            RepairCode repairCode = repairCodeService.getById(repairCodeId);
            if (repairCode == null) {
                throw new ApiException("选择的车辆暂不可用,请重新选择!");
            }
            electricVehBrandId = repairCode.getElectricVehBrandId();
        } else {
            electricVehBrandId = form.getElectricVehBrandId();
        }
        SysElectricVehBrand electricVehBrand = electricVehBrandService.getById(electricVehBrandId);
        if (electricVehBrand == null) {
            throw new ApiException("选择的车辆或者电瓶暂不可用,请重新选择!");
        }
        deposit = electricVehBrand.getRent();
        return deposit;
    }

    /**
     * 获取品牌资费
     * repairCodeId: 车辆ID electricVehBrandId: 电池
     *
     * @return
     */
    private SysElectricVehBrand getElectricVehBrand(Byte lease, Long repairCodeId, Long electricVehBrandId, Long shopId) {
        Long id = electricVehBrandId;
        if (lease.intValue() == 1) {
            RepairCode repairCode = repairCodeService.getById(repairCodeId);
            if (repairCode == null) {
                throw new ApiException("车辆信息null!");
            }
            id = repairCode.getElectricVehBrandId();
        }
//        if (repairCodeId == null && electricVehBrandId == null) {
//            log.error("【获取品牌资费失败,参数错误】");
//            throw new MyException("电池或车辆信息null!");
//        }
//        Long id = electricVehBrandId;
//        if (id == null) {
//            RepairCode repairCode = repairCodeService.getById(repairCodeId);
//            id = repairCode.getElectricVehBrandId();
//        }
        List<SysElectricVehBrand> electricVehBrands = electricVehBrandService.list(new LambdaQueryWrapper<SysElectricVehBrand>()
                .eq(SysElectricVehBrand::getShopId, shopId)
                .eq(SysElectricVehBrand::getId, id));
        if (CollectionUtils.isEmpty(electricVehBrands)) {
            log.error("【获取品牌资费失败,参数错误】");
            throw new MyException("获取品牌资费失败,参数错误");
        }
//        SysElectricVehBrand brandServiceById = electricVehBrandService.getById(id);
//        if (brandServiceById == null) {
//            log.error("【获取品牌资费失败,参数错误】");
//            throw new MyException("获取品牌资费失败,参数错误");
//        }
        return electricVehBrands.get(0);
    }

    /***
     * 申请租车(生成合同)
     * @param form
     * @return
     */
    @Override
    public boolean createContract(CarRentalCostsForm form, HttpServletRequest request) {
        DtsCarRental carRental = getById(form.getId());
        if (1 != carRental.getIsPayed().intValue()) {
            throw new ApiException("租车订单暂未支付, 请先支付后在提交!");
        }
        //生成合同编号
        DtsCarRental dtsCarRental = new DtsCarRental();
        BeanUtils.copyProperties(form, dtsCarRental);
        dtsCarRental.setAdminId(SecurityUtils.getUserId());
        dtsCarRental.setSubDate(new Date());
        dtsCarRental.setStatus((byte) 1);
        dtsCarRental.setGuaranteeCompanyId(form.getGuaranteeCompanyId());
        String contractType = getContractType(form); //合同编号规则
        dtsCarRental.setContractType(contractType);
        String contractNo = getContractNo(carRental.getShopId()); //获取合同编号
        dtsCarRental.setContractNo(contractNo);
        dtsCarRental.setSubDate(new Date());
        //合同数据
        ContractData contractData = getContractData(form.getId(), form.getRepairCodeId(), form.getElectricVehBrandId(), form.getGuaranteeCompanyId(), contractNo, "", null);
        String content = getContent(contractData, request);
        //获取html内容合同
        //String htmlContent = getHtmlContent(form.getUserId(), form.getId(), "", form.getRepairCodeId(), form.getElectricVehBrandId(), request);
        dtsCarRental.setContent(content);
        //int count = dtsCarRentalMapper.updateByPrimaryKeySelective(dtsCarRental);
        //return updateById(dtsCarRental);
        boolean update = updateById(dtsCarRental);
        if (update) {
            if (form.getRepairCodeId() != null) { //修改车辆状态
                updateRepairCodeStatus(form.getRepairCodeId(), (byte) 4);
            }
            return true;
        }
        return false;
    }


    /***
     * 获取合同编号类型
     * 合同编号规则：
     * 电池：
     * 	骑遇：Q日期-0001
     * 	骑缘：P2022-3-4-0001
     * 整车：
     * 	骑遇：QY2022-3-4-0001
     * 	骑缘：PQ2022-3-4-0001
     * @param form
     * @return
     */
    public String getContractType(CarRentalCostsForm form) {
        String contractType = "";
        if (SysConstants.QIYU == form.getType().intValue()) {
            if (form.getRepairCodeId() != null) {
                contractType = "QY"; //骑遇整车
            } else {
                contractType = "Q";//骑遇电池
            }
        } else {
            if (form.getRepairCodeId() != null) {
                contractType = "PQ"; //骑缘整车
            } else {
                contractType = "P";//骑缘电池
            }
        }
        return contractType;
    }


    /***
     * 修改车辆为暂租
     * @param repairCodeId
     */
    private void updateRepairCodeStatus(Long repairCodeId, Byte status) {
        RepairCode serviceById = repairCodeService.getById(repairCodeId);
        if (serviceById == null) {
            throw new MyException("操作失败，参数错误");
        }
        RepairCode repairCode = new RepairCode();
        repairCode.setId(repairCodeId);
        repairCode.setVehicleStatus(status);
        repairCode.setRentUser(null);
        repairCode.setVehicleBelongs(serviceById.getVehicleBelongs());
        repairCodeService.updateByPrimaryKeySelective(repairCode);
    }


    /***
     * 获取合同数据
     * @return
     */
    public ContractData getContractData(Long id, Long repairCodeId, Long electricVehBrandId, Long guaranteeCompanyId, String contractNo, String userSign, Long communityId) {
        ContractData contractData = new ContractData();
        contractData.setContractNo(contractNo);
        //合同订单
        DtsCarRental carRental = getById(id);
        Long userId = carRental.getUserId();
        DtsUser dtsUser = dtsUserService.getById(userId);
        Long shopId = SecurityUtils.getLoginUser().getShopId();
        SysContract sysContract = sysContractService.getOne(new LambdaQueryWrapper<SysContract>()
                .eq(SysContract::getShopId, shopId));
        contractData.setLessor(sysContract.getLessor());
        if (communityId == null) {
            DtsUser adminUser = dtsUserService.getById(SecurityUtils.getUserId());
            communityId = adminUser.getCommunityId();
        }
        //站点ID
        SysCommunity sysCommunity = sysCommunityService.getById(communityId);
        contractData.setSiteMgrPhn(sysCommunity.getSiteMobile());
        contractData.setRealName(dtsUser.getRealName());
        contractData.setIdCard(dtsUser.getIdCard());
        contractData.setMobile(dtsUser.getMobile());
        contractData.setEmergencyContact(dtsUser.getEmergencyContact() == null ? "　" : dtsUser.getEmergencyContact());
        contractData.setBatterySwapId(dtsUser.getBatteryId() == null ? "　" : dtsUser.getBatteryId());
        String vehicleNumber = "";
        Byte productType = (byte) 1;
        if (repairCodeId != null) {
            RepairCode repairCode = repairCodeService.getById(repairCodeId);
            vehicleNumber = repairCode.getVehicleNumber();
        } else if (electricVehBrandId != null) {
            SysElectricVehBrand electricVehBrand = electricVehBrandService.findById(electricVehBrandId, shopId);
            vehicleNumber = electricVehBrand.getName();
            productType = (byte) 2;
        }
        contractData.setVehicleNumber(vehicleNumber);
        if (guaranteeCompanyId != null) {
            String guaranteeCompanyServiceName = guaranteeCompanyService.getNameById(guaranteeCompanyId);
            contractData.setGuaranteeCompany(guaranteeCompanyServiceName);
            GuaranteeSite guaranteeSite = guaranteeSiteService.getGuaranteeSiteByUserId(dtsUser.getIdCard());
            if (guaranteeSite != null) {
                contractData.setGuaranteeSite(guaranteeSite.getName());
            }
        } else {
            contractData.setGuaranteeCompany("　");
            contractData.setGuaranteeSite("　");
        }
        contractData.setProductType(productType);
        //起租日期
        String leaseStartDate = MyDateUtils.getDateString(carRental.getSubDate() == null ? new Date() : carRental.getSubDate());
        contractData.setStartDate(leaseStartDate);
        contractData.setContractPlace(sysCommunity.getAddress());
        contractData.setPartyStamp(sysContract.getOfclSeal());
        contractData.setUserSign(userSign);
        //List<SysPostage> postageList = sysPostageService.list();
        SysElectricVehBrand electricVehBrand = null;
        if (electricVehBrandId != null) {
            electricVehBrand = electricVehBrandService.findById(electricVehBrandId, shopId);
        } else if (repairCodeId != null) {
            electricVehBrand = electricVehBrandService.getByRepairCodeId(repairCodeId);
        }
        contractData.setElectricVehBrand(electricVehBrand);
        redisUtils.setCacheObject("contractData:" + id, JSON.toJSONString(contractData), 1, TimeUnit.DAYS);
        return contractData;
    }

    /***
     * 获取合同html内容
     * @param contractData
     * @param request
     * @return
     */
    public String getContent(ContractData contractData, HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        //创建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", authorization);
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        String url = "http://lease-server";
        url += "/sys/contract/create";
        String paramJosn = JSON.toJSONString(contractData);
        HttpEntity entity = new HttpEntity<>(paramJosn, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
        String content = responseEntity.getBody();
        return content;
    }


    /***
     * 根据当前登录用户获取租车信息
     * @return
     */
    @Override
    public UserCarRental getCarRentalByUser() {
        Long userId = SecurityUtils.getUserId();
        UserCarRental userCarRental = dtsCarRentalMapper.getCarRentalByUser(userId);
        if (userCarRental != null && userCarRental.getRepairCodeId() != null) {
            userCarRental.setType((byte) 1);
            userCarRental.setVehicleNumber(userCarRental.getRepairCode() != null ? userCarRental.getRepairCode().getVehicleNumber() : "未知");
        } else if (userCarRental != null && userCarRental.getElectricVehBrandId() != null) {
            SysElectricVehBrand electricVehBrand = electricVehBrandService.getById(userCarRental.getElectricVehBrandId());
            userCarRental.setType((byte) 2);
            userCarRental.setVehicleNumber(electricVehBrand != null ? electricVehBrand.getName() : "未知");
        }
        return userCarRental;
    }

    /***
     * 关闭合同
     * @param id
     * @return
     */
    @Override
    public boolean closeContract(Long id) {
        DtsCarRental carRental = getById(id);
        if (carRental == null) {
            throw new MyException("关闭合同失败,ID无效");
        }
        if (carRental.getRepairCodeId() != null) {
            //修改车辆状态
            updateRepairCodeStatus(carRental.getRepairCodeId(), (byte) 1);
        }
        //关闭扣费表
        closureUserDeduction(carRental.getUserId());
        DtsCarRental carRentalDB = new DtsCarRental();
        carRentalDB.setId(id);
        carRentalDB.setStatus((byte) 4);
        return updateById(carRentalDB);
    }


    /***
     * 分页查询在租明细
     * @param page
     * @param query
     * @return
     */
    @Override
    public Map<String, Object> carRentalDetails(Page<DtsCarRental> page, Long shopId, SysCarRentalQuery query) {
        Long userId = SecurityUtils.getUserId();
        SysUser user = sysUserService.getById(userId);
        if (user == null || user.getCommunityId() == null) {
            return new HashMap<>();
        }
        if (user.getCommunityId() != 1L) {
            query.setAdminCommunityId(user.getCommunityId());
        }
        query.setStatus((byte) 3);
        Map<String, Object> result = sysFindByPage(page, shopId, query);
        if (!result.isEmpty() && result.get("records") != null) {
            List<SysDtsCarRentalVo> records = (List<SysDtsCarRentalVo>) result.get("records");
            List<Long> companyIds = new ArrayList<>();
            //CarRentalGuaranteeSite 担保信息
            List<String> idCards = records.stream().map(SysDtsCarRentalVo::getIdCard).collect(Collectors.toList());
            //担保公司查询
            List<GuaranteeSiteUser> guaranteeSiteUsers = guaranteeSiteService.findByIdCards(idCards);
            for (SysDtsCarRentalVo record : records) {
                record.setContent("");
                //设置担保公司
                if (!CollectionUtils.isEmpty(guaranteeSiteUsers)) {
                    for (GuaranteeSiteUser guaranteeSiteUser : guaranteeSiteUsers) {
                        if (guaranteeSiteUser.getIdCard().equals(record.getIdCard())) {
                            record.setGuaranteeCompanyName(guaranteeSiteUser.getGuaranteeCompany());
                            record.setGuaranteeSiteName(guaranteeSiteUser.getGuaranteeSite());
                        }
                    }
                }
            }
            List<Long> list = records.stream().map(SysDtsCarRentalVo::getId).collect(Collectors.toList());
            List<CarRentalRepairMaint> carRentalRepairMaints = repairMaintService.listByCarRetreatIds(list);
            if (!CollectionUtils.isEmpty(carRentalRepairMaints)) {
                for (SysDtsCarRentalVo record : records) {
                    List<CarRentalRepairMaint> carRentalRepairMaintList = new ArrayList<>();
                    BigDecimal maintFees = new BigDecimal("0");
                    for (CarRentalRepairMaint carRentalRepairMaint : carRentalRepairMaints) {
                        if (record.getId().equals(carRentalRepairMaint.getCarRentalId())) {
                            maintFees = maintFees.add(carRentalRepairMaint.getPrice());
                            carRentalRepairMaintList.add(carRentalRepairMaint);
                        }
                    }
                    record.setMaintFees(maintFees);
                    record.setCarRentalRepairMaints(carRentalRepairMaintList);
                }
            }
        }
        return result;
    }

    /***
     * 导出台账
     * @param response
     * @param query
     * @return
     */
    @Override
    public void exportLedger(HttpServletResponse response, Long shopId, SysCarRentalQuery query) {
        Long userId = SecurityUtils.getUserId();
        SysUser user = sysUserService.getById(userId);
        if (user == null || user.getCommunityId() == null) {
            return;
        }
        if (user.getCommunityId() != 1L) {
            query.setAdminCommunityId(user.getCommunityId());
        }
        List<LedgerData> ledgerDataList = dtsCarRentalMapper.findLedger(shopId, query);
        if (CollectionUtils.isEmpty(ledgerDataList)) {
            return;
        }
        if (!CollectionUtils.isEmpty(ledgerDataList)) {
            //维修费
            List<Long> list = ledgerDataList.stream().map(LedgerData::getId).collect(Collectors.toList());
            List<CarRentalRepairMaint> carRentalRepairMaints = repairMaintService.listByCarRetreatIds(list);
            //CarRentalGuaranteeSite 担保信息
            List<String> idCards = ledgerDataList.stream().map(LedgerData::getIdCard).collect(Collectors.toList());
            //担保公司查询
            List<GuaranteeSiteUser> guaranteeSiteUsers = guaranteeSiteService.findByIdCards(idCards);
            //车辆 电瓶 资费
            List<Long> ids = new ArrayList<>();
            for (LedgerData ledgerData : ledgerDataList) {
                if (ledgerData.getElectricVehBrandId() != null) {
                    ids.add(ledgerData.getElectricVehBrandId());
                }
                if (ledgerData.getRepairCodeId() != null) {
                    ids.add(ledgerData.getRepairCodeId());
                }
            }
            //资费查询
            List<CarRentalFee> carRentalFees = electricVehBrandService.findByIdAndRepairCodeId(ids);
            for (LedgerData ledgerData : ledgerDataList) {
                //设置维修费
                if (!CollectionUtils.isEmpty(carRentalRepairMaints)) {
                    BigDecimal maintFees = new BigDecimal("0");
                    List<CarRentalRepairMaint> carRentalRepairMaintList = new ArrayList<>();
                    for (CarRentalRepairMaint carRentalRepairMaint : carRentalRepairMaints) {
                        if (ledgerData.getId().equals(carRentalRepairMaint.getCarRentalId())) {
                            maintFees = maintFees.add(carRentalRepairMaint.getPrice());
                            carRentalRepairMaintList.add(carRentalRepairMaint);
                        }
                    }
                    ledgerData.setMaintFees(maintFees);
                    ledgerData.setCarRentalRepairMaintList(carRentalRepairMaintList);
                }
                //设置担保公司
                if (!CollectionUtils.isEmpty(guaranteeSiteUsers)) {
                    for (GuaranteeSiteUser guaranteeSiteUser : guaranteeSiteUsers) {
                        if (guaranteeSiteUser.getIdCard().equals(ledgerData.getIdCard())) {
                            ledgerData.setGuaranteeCompanyName(guaranteeSiteUser.getGuaranteeCompany());
                            ledgerData.setGuaranteeSite(guaranteeSiteUser.getGuaranteeSite());
                        }
                    }
                }
                //设置资费
                if (!CollectionUtils.isEmpty(carRentalFees)) {
                    for (CarRentalFee carRentalFee : carRentalFees) {
                        if (carRentalFee.getId().equals(ledgerData.getElectricVehBrandId()) ||
                                carRentalFee.getId().equals(ledgerData.getRepairCodeId())) {
                            ledgerData.setCarRentalFee(carRentalFee);
                        }
                    }
                }
            }
        }

        log.info("[ledgerDataList]: {}", JSON.toJSONString(ledgerDataList));

        for (int i = 0; i < ledgerDataList.size(); i++) {
            LedgerData ledgerData = ledgerDataList.get(i);
            ledgerData.setId(Long.valueOf(1 + i));
            if (ledgerData != null && ledgerData.getCarRentalFee() != null) {
                ledgerData.setRentStandard(ledgerData.getCarRentalFee().getRent());
            }
        }

        log.info("【" + MyDateUtils.getCurDt() + "导出台账：】{}", JSON.toJSONString(ledgerDataList));
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(MyDateUtils.getCurDt() + "台账", MyDateUtils.getCurDt()), LedgerData.class, ledgerDataList);
        try {
            response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(MyDateUtils.getCurDt() + "台账.xls", "UTF-8"));
            ServletOutputStream os = response.getOutputStream();
            workbook.write(os);
            os.close();
            workbook.close();
        } catch (IOException e) {
            log.error("【导出台账,错误】{}", JSON.toJSONString(e, true));
        }

    }

    /***
     * 导出合同
     * @param id
     * @param response
     */
    @Override
    public void exportContract(Long id, HttpServletResponse response) {
        ServletOutputStream os = null;
        try {
            Resource resource = new ClassPathResource("contract.jasper");
            InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream("contract.jasper");
            //FileInputStream fis = new FileInputStream();
            log.info("读取jasper成功");
            //2.创建JasperPrint,向jasper文件中填充数据
            os = response.getOutputStream();
            Map parameters = new HashMap<>();
            //设置参数 参数的key = 模板中使用的parameters参数的name
            DtsCarRental carRental = getById(id);
            if (carRental == null) {
                log.error("【导出合同失败, 租车申请ID不存在】");
                throw new MyException("导出合同失败");
            }
            if (StringUtils.isEmpty(carRental.getUserSign())) {
                log.error("【导出合同失败,用户暂未签字！】");
                throw new MyException("导出合同失败,用户暂未签字！");
            }
            ContractData contractData = getContractData(id,
                    carRental.getRepairCodeId(),
                    carRental.getElectricVehBrandId(),
                    carRental.getGuaranteeCompanyId(),
                    carRental.getContractNo(),
                    "",
                    carRental.getCommunityId());
            Map<String, Object> contractDataMap = BeanMapUtils.beanToMap(contractData);
            String productType = carRental.getLease() == 1 ? "整车" : "电池";
            contractDataMap.put("productType", productType);
            contractDataMap.put("partyStamp", minioEndpoint + "/" + contractData.getPartyStamp());
            contractDataMap.put("userSign", minioEndpoint + "/" + carRental.getUserSign());
            String electricVehBrand = "";
            if (contractData != null && contractData.getElectricVehBrand() != null) {
                electricVehBrand =
                        "成本价:￥" + contractData.getElectricVehBrand().getCostPrice()
                                + " 押金:￥" + carRental.getDeposit()
                                + " 最低租金:￥" + contractData.getElectricVehBrand().getRent()
                                + " 日租金:￥" + contractData.getElectricVehBrand().getDayRent()
                                + " 总共支付:￥" + carRental.getTotalRent();
                contractDataMap.put("electricVehBrand", electricVehBrand);
            }
            log.info("contractDataMap: {}", JSON.toJSONString(contractDataMap, true));
            JasperPrint print = JasperFillManager.fillReport(fis, contractDataMap, new JREmptyDataSource());
            //3.将JasperPrint已PDF的形式输出
            JasperExportManager.exportReportToPdfStream(print, os);
        } catch (Exception e) {
            log.error("【导出合同错误】：{}", JSON.toJSONString(e, true));
        } finally {
            if (os != null) {
                try {
                    os.flush();
                } catch (IOException e) {
                    log.error("【导出合同错误】：{}", JSON.toJSONString(e, true));
                }
            }

        }

    }

    /***
     * 导出今日租车明细
     * @param response
     */
    @Override
    public void export(HttpServletResponse response, Long shopId, String contractNo, String idCard, String mobile, String realName, Long communityId) {
        List<DtsCarRentalExcel> carRentalExcels = this.dtsCarRentalMapper.leaseDetails(shopId, contractNo, idCard, mobile, realName, communityId);
        //log.info("【" + MyDateUtils.getCurDt() + "租车明细：】{}", JSON.toJSONString(carRentalExcels, true));
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(MyDateUtils.getCurDt() + "租车明细", MyDateUtils.getCurDt()), DtsCarRentalExcel.class, carRentalExcels);
        try {
            response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(MyDateUtils.getCurDt() + "租车明细.xls", "UTF-8"));
            ServletOutputStream os = response.getOutputStream();
            workbook.write(os);
            os.close();
            workbook.close();
        } catch (IOException e) {
            log.error("【导出今日租车明细,错误】{}", JSON.toJSONString(e, true));
        }
    }

    /**
     * 查询租车量
     *
     * @param shopId
     * @return
     */
    @Override
    public Map<String, Integer> carRentalCount(Long shopId) {
        return dtsCarRentalMapper.carRentalCount(shopId);
    }

    /**
     * 查询租车合同公司
     *
     * @param userId
     * @return
     */
    @Override
    public ContractDto findCarRentalContract(Long userId) {
        return dtsCarRentalMapper.findCarRentalContract(userId);
    }


    @Override
    public boolean stopRep(Long id) {
        DtsCarRental dtsCarRental = getById(id);
        if (3 != Integer.valueOf(dtsCarRental.getStatus())) {
            throw new ApiException("订单不是在租状态,不能报停!");
        }
        if (0 != dtsCarRental.getStopRep()) {
            throw new ApiException("订单已报停,无需重复操作!");
        }
        //暂停扣费
        dtsUserDeductionService.stopUserDeduction(dtsCarRental.getUserId());
        //释放车辆
        if (1 == dtsCarRental.getLease()) {
            closeCar(dtsCarRental.getRepairCodeId());
        }
        dtsCarRental.setStopRep(1);
        return updateById(dtsCarRental);
    }


    /**
     * 恢复租车状态
     *
     * @return
     */
    @Override
    public boolean recovery(Map<String, Long> param, HttpServletRequest request) {
        DtsCarRental dtsCarRental = getById(param.get("id"));
        if (3 != Integer.valueOf(dtsCarRental.getStatus())) {
            throw new ApiException("订单不是在租状态,不能恢复!");
        }
        if (0 == dtsCarRental.getStopRep()) {
            throw new ApiException("订单已恢复,无需重复操作!");
        }
        //更改车辆状态
        if (1 == dtsCarRental.getLease()) {
            Long repairCodeId = param.get("repairCodeId");
            dtsCarRental.setRepairCodeId(repairCodeId);
            repairCodeLease(repairCodeId, dtsCarRental.getUserId());
            //更改合同
            //合同数据
            ContractData contractData = getContractData(dtsCarRental.getId(),
                    repairCodeId,
                    dtsCarRental.getElectricVehBrandId(),
                    dtsCarRental.getGuaranteeCompanyId(),
                    dtsCarRental.getContractNo(),
                    dtsCarRental.getUserSign(),
                    dtsCarRental.getCommunityId());
            String content = getContent(contractData, request);
            //log.info("【更改合同数据】: {}", content);
            dtsCarRental.setContent(content);
        }
        //恢复扣费表
        dtsUserDeductionService.recoveryUserDeduction(dtsCarRental.getUserId());
        dtsCarRental.setStopRep(0);
        return updateById(dtsCarRental);
    }

    /**
     * 设置车辆出租人
     *
     * @param repairCodeId
     * @param userId
     */
    public void repairCodeLease(Long repairCodeId, Long userId) {
        RepairCode repairCode = new RepairCode();
        repairCode.setId(repairCodeId);
        repairCode.setVehicleStatus((byte) 4);
        repairCode.setRentUser(userId);
        repairCodeService.updateById(repairCode);
    }

    /***
     * 关闭扣费表
     * @param userId
     */
    private void closureUserDeduction(Long userId) {
        //DtsCarRetreat dtsCarRetreat = getById(id);
        dtsUserDeductionService.remove(new LambdaQueryWrapper<DtsUserDeduction>()
                .eq(DtsUserDeduction::getUserId, userId));
    }


    /***
     * 获取合同编号
     * @param shopId
     * @return
     */
    private String getContractNo(Long shopId) {
        String contractNo = dtsCarRentalMapper.maxContractNo(shopId);
        return MyStringUtils.getSerlNum2(contractNo);
    }

    /**
     * 用户签名
     *
     * @return
     */
    @Override
    public boolean usrSignature(Long id, String userSign, HttpServletRequest request) {
        DtsCarRental carRental = getById(id);
        if (carRental == null) {
            throw new MyException("参数错误");
        }
        String contractDataJson = redisUtils.getCacheObject("contractData:" + id);
        if (StringUtils.isEmpty(contractDataJson)) {
            DtsCarRental dtsCarRental = getById(id);
            ContractData contractData = getContractData(id, dtsCarRental.getRepairCodeId(), dtsCarRental.getElectricVehBrandId(), dtsCarRental.getGuaranteeCompanyId(), dtsCarRental.getContractNo(), userSign, null);
            contractDataJson = JSON.toJSONString(contractData);
        }
        ContractData contractData = JSON.parseObject(contractDataJson, ContractData.class);
        contractData.setUserSign(userSign);
        String content = getContent(contractData, request);
        //String htmlContent = getHtmlContent(carRental.getUserId(), id, sign, carRental.getRepairCodeId(), carRental.getElectricVehBrandId(), request);
        DtsCarRental dtsCarRental = new DtsCarRental();
        dtsCarRental.setId(id);
        dtsCarRental.setStatus((byte) 2);
        dtsCarRental.setUserSign(userSign);
        dtsCarRental.setContent(content);
        dtsCarRental.setApprovalTime(new Date());
        //更新用户余额
        //updUserBal(id);
        if (carRental.getLease().intValue() == 1) {
            //设置车辆状态为出租
            updRepairCodeStatus(id);
        }
        return updateById(dtsCarRental);
    }


    /***
     * 后台管理员查询租车申请
     * @param page
     * @return
     */
    @Override
    public Map<String, Object> sysFindByPage(Page<DtsCarRental> page, Long shopId, SysCarRentalQuery query) {
        PageHelper.startPage((int) page.getCurrent(), (int) page.getSize());
        List<SysDtsCarRentalVo> sysDtsCarRentalVoList = dtsCarRentalMapper.sysFindByPage(shopId, query);
        PageInfo<SysDtsCarRentalVo> pageInfo = new PageInfo<>(sysDtsCarRentalVoList);
        Map<String, Object> result = new HashMap<>();
        result.put("total", (int) pageInfo.getTotal());
        result.put("records", pageInfo.getList());
        return result;
    }


    /***
     * 后台管理员审核租车申请
     * @param id 当前申请ID
     * @param status 审核状态 0:不通过 1:通过
     * @param auditOpinion 审核意见
     * @return
     */
    @Override
    public boolean audit(Long id, Byte status, String auditOpinion) {
        DtsCarRental carRental = getById(id);
        if (carRental.getStatus().intValue() == 3) {
            throw new MyException("当前租车申请已通过，不可重复审核");
        }
        Byte auditStatus = getStatus(status, id);
        DtsCarRental dtsCarRental = new DtsCarRental();
        dtsCarRental.setStatus(auditStatus);
        dtsCarRental.setId(id);
        dtsCarRental.setAuditOpinion(auditOpinion);
//        dtsCarRental.setModifyBy(SecurityUtils.getUserId());
        if (auditStatus.intValue() == 3) {
            dtsCarRental.setApprovalTime(new Date());
            //生成每日扣费表
            initUserDeduction(carRental.getUserId(), carRental.getDayRent());
            //记录账单表
            saveUserBill(carRental.getUserId(), carRental.getDayRent());
            //跟新用户余额
            updUserBal(id);
        } else {
            //审核驳回给用户退费
            rfnd(id, carRental.getShopId(), auditOpinion, carRental.getOrderNumber());
            //释放车辆
            if (carRental.getLease() == 1) {
                closeCar(carRental.getRepairCodeId());
            }
        }
        return updateById(dtsCarRental);
    }


    /***
     * 释放新车
     * @param id
     */
    private void closeCar(Long id) {
//        RepairCode repairCode = new RepairCode();
//        repairCode.setId(id);
//        repairCode.setStatus((byte) 1);
//        repairCode.setVehicleStatus((byte) 1);
//        repairCodeService.updateByPrimaryKeySelective(repairCode);
        repairCodeService.closeRepairCode(id);
    }

    /**
     * 用户退费
     *
     * @param id
     */
    private void rfnd(Long id, Long shopId, String auditOpinion, String orderNumber) {
        DtsCarRentalRefund rentalRefund = dtsCarRentalRefundService.getOne(new LambdaQueryWrapper<DtsCarRentalRefund>()
                .eq(DtsCarRentalRefund::getOrderNumber, orderNumber));
        if (rentalRefund != null) {
            String payNo = IdWorker.getId() + "";
            log.info("【用户租车驳回退费 payNo：{}】", payNo);
            String refundNo = rentalRefund.getOutRefundNo();
            Double fee = rentalRefund.getOrderAmount();
            String notifyUrl = "/lease/dts/carRetreat/rvwRejected/refund/notify";
            payService.carRetreat(shopId, rentalRefund.getAppId(), payNo, refundNo, fee, fee, notifyUrl, auditOpinion);
            dtsCarRentalMapper.updateIsPay(id);
        }
    }

    @Override
    public BigDecimal getUserbalance(Long carRentalId) {
        return dtsCarRentalMapper.getUserbalance(carRentalId);
    }


    /***
     * 审核状态 0:不通过 1:通过
     * @param status
     * @return
     */
    private Byte getStatus(Byte status, Long id) {
        if (status.intValue() == 1) {
            //更新用户余额
            //updUserBal(id);
            //设置车辆状态
            //updRepairCodeStatus(id);
            return (byte) 3;
        }
        return (byte) 0;
    }

    /***
     * 设置车辆状态
     * @param id
     */
    private void updRepairCodeStatus(Long id) {
        DtsCarRental dtsCarRental = getById(id);
        RepairCode repairCode = repairCodeService.getById(dtsCarRental.getRepairCodeId());
        //状态 1:正常 2:故障 3:报废 4:出租
        repairCode.setVehicleStatus((byte) 4);
        repairCode.setRentUser(dtsCarRental.getUserId());
        repairCodeService.updateById(repairCode);
    }

    /**
     * 记录账单表
     */
    private void saveUserBill(Long userId, BigDecimal amount) {
        DtsUserBill dtsUserBill = new DtsUserBill();
        long billId = IdWorker.getId();
        dtsUserBill.setId(billId);
        dtsUserBill.setType((byte) 3);
        dtsUserBill.setUserId(userId);
        dtsUserBill.setAmount(amount.negate());
        dtsUserBill.setCreated(new Date());
        dtsUserBillService.save(dtsUserBill);
    }

    /***
     * 更新用户余额
     * @param id
     */
    private void updUserBal(Long id) {
        DtsCarRental dtsCarRental = getById(id);
        Long userId = dtsCarRental.getUserId();
        BigDecimal dayRent = dtsCarRental.getDayRent();
        //initUserDeduction(userId, dayRent);
        //更新用户余额
        DtsUser dtsUser = dtsUserService.getById(userId);
        dtsUser.setBalance(dtsCarRental.getTotalRent().subtract(dayRent).subtract(dtsCarRental.getDeposit()));
        dtsUser.setDeposit(dtsCarRental.getDeposit());
        dtsUserService.updateById(dtsUser);
    }

    //租车成功后新增系统扣费表
    private void initUserDeduction(Long userId, BigDecimal amount) {
        DtsUserDeduction dtsUserDeduction = new DtsUserDeduction();
        dtsUserDeduction.setId(IdWorker.getId());
        dtsUserDeduction.setUserId(userId);
        dtsUserDeduction.setRent(amount.abs());
        dtsUserDeduction.setStatus((byte) 1);
        dtsUserDeduction.setCreated(new Date());
        dtsUserDeductionService.save(dtsUserDeduction);
    }


    /***
     * 根据租车ID获取用户信息
     * @param userId
     * @return
     */
    private DtsUser getDtsUserById(Long userId) {
//        DtsCarRental dtsCarRental = getById(id);
//        if (dtsCarRental == null) {
//            throw new MyException("参数错误,ID无效!");
//        }
        DtsUser dtsUser = dtsUserService.getById(userId);
        if (dtsUser == null) {
            throw new MyException("参数错误,用户ID无效!");
        }
        return dtsUser;
    }


    /***
     * 获取资费配置
     * @param type
     * @param code
     * @return
     */
    private SysPostage getSysPostage(int type, String code) {
        return postageService.getOne(new LambdaQueryWrapper<SysPostage>()
                .eq(SysPostage::getType, type)
                .eq(SysPostage::getCode, code));
    }

    /****
     * 根据id获取车辆
     * @param repairCodeId
     * @return
     */
    private RepairCode getRepairCodeById(Long repairCodeId) {
        return repairCodeService.getById(repairCodeId);
    }


    /***
     * 获取担保公司
     * @param form
     * @return
     */
    private GuaranteeCompany getGuaranteeCompanyById(CarRentalCostsForm form) {
        GuaranteeCompany guaranteeCompany = null;
        if (form.getGuaranteeCompanyId() != null) {
            guaranteeCompany = guaranteeCompanyService.getById(form.getGuaranteeCompanyId());
        }
        return guaranteeCompany;
    }


    /**
     * 校验参数
     *
     * @param form
     */
    private void check(CarRentalCostsForm form) {
        //校验押金 保单公司
        if (getGuaranteeCompanyById(form) == null) {
            if (form.getDeposit() == null || new BigDecimal(1000).compareTo(new BigDecimal(form.getDeposit().toString())) > 0) {
                throw new MyException("该用户无担保公司,押金必须大于等于1000!");
            }
        }
        DtsCarRental carRental = getById(form.getId());
        if (carRental.getIsPayed() == 1) {
            throw new ApiException("您已支付,可以签署了◠‿◠");
        }
        /*if (form.getType().intValue() == 2 && form.getRepairCodeId() != null && getGuaranteeCompanyById(form) != null) {
            if (form.getRent() == null || new BigDecimal(200).compareTo(new BigDecimal(form.getRent().toString())) > 0) {
                throw new MyException("骑缘整合租金必须大于等于200!");
            }
        }*/

    }

}
